package vcp.client.utility;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.util.Iterator;

import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;

import vcp.entity.Lot;
import vcp.entity.Site;
import vcp.enums.Floor;

import com.itextpdf.text.BadElementException;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.Font;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.Phrase;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfWriter;

/**
 * 
 * @author VCP team
 *         <p>
 *         Responsible for generating PDFs
 *         </p>
 */
public class PdfGenerator
{
	// ****************************************************************************************************************************
	// Constants
	// ****************************************************************************************************************************
	private final static String PATH = "VCP_";
	private final static String EXTENTION = ".pdf";

	private final static String TITLE = "VCP system.";

	private final static String TABLE_HEADER_ROW = "Row";
	private final static String TABLE_HEADER_COLUMN = "Column";
	private final static String TABLE_HEADER_STATUS = "Status";

	private final static Font mainPageHeaderFont = new Font(Font.FontFamily.TIMES_ROMAN, 40, Font.BOLD | Font.UNDERLINE);
	private final static Font siteNameFont = new Font(Font.FontFamily.TIMES_ROMAN, 30, Font.BOLD);
	private final static Font floorFont = new Font(Font.FontFamily.TIMES_ROMAN, 12, Font.BOLD);

	/** limits constructor to package only **/
	protected PdfGenerator ()
	{
	}

	// ****************************************************************************************************************************
	// Public methods
	// ****************************************************************************************************************************
	/**
	 * Saves site's information to PDF format
	 * 
	 * @param site
	 *            information of which will be download to PDF
	 * @param timeStamp
	 *            current time
	 * @return true if save was success
	 */
	public boolean saveToPDF ( Site site, DateTime timeStamp )
	{
		boolean success = true;
		try
		{
			String name = this.extractFileName(timeStamp);
			Document document = this.openPDFDocument(name);

			this.addMainPage(document, site.getSiteName());
			this.addContent(document, site);

			this.closePDFDocument(document);
		}
		catch ( Exception e )
		{
			e.printStackTrace();
			success = false;
		}
		return success;
	}

	// ****************************************************************************************************************************
	// Private methods
	// ****************************************************************************************************************************
	/**
	 * @param name
	 *            of created PDF file
	 * @return document to process as PDF
	 * @throws FileNotFoundException
	 * @throws DocumentException
	 */
	private Document openPDFDocument ( String name )
			throws FileNotFoundException, DocumentException
	{
		Document document = new Document();
		PdfWriter.getInstance(document, new FileOutputStream(name));
		document.open();

		return document;
	}

	/**
	 * 
	 * @param document
	 *            to close
	 */
	private void closePDFDocument ( Document document )
	{
		document.close();
	}

	/**
	 * 
	 * @param dateTime
	 *            stamp as part of name
	 * @return name for new PDF
	 */
	private String extractFileName ( DateTime dateTime )
	{
		return PdfGenerator.PATH
				+ DateTimeFormat
						.forPattern("dd.MM.YYYY____HH_mm")
						.print(dateTime)
				+ PdfGenerator.EXTENTION;
	}

	/**
	 * 
	 * @param document
	 *            created PDF object
	 * @param siteName
	 *            will be added to main page
	 * @throws DocumentException
	 */
	private void addMainPage ( Document document, String siteName )
			throws DocumentException
	{
		// main paragraph
		Paragraph preface = new Paragraph();

		// adding spacing
		this.addEmptyLine(preface, 15);

		// main title paragraph
		Paragraph headerParagraph = new Paragraph(PdfGenerator.TITLE, PdfGenerator.mainPageHeaderFont);
		headerParagraph.setAlignment(Element.ALIGN_CENTER);
		preface.add(headerParagraph);

		// adding spacing
		this.addEmptyLine(preface, 5);

		// adding site name to main page
		Paragraph siteNameParagraph = new Paragraph(siteName, PdfGenerator.floorFont);
		siteNameParagraph.setAlignment(Element.ALIGN_CENTER);
		preface.add(siteNameParagraph);

		// adding main paragraph to PDF object
		document.add(preface);
		document.newPage();
	}

	/**
	 * 
	 * @param document
	 *            created PDF object
	 * @param site
	 *            from which information will be download
	 * @throws DocumentException
	 */
	private void addContent ( Document document, Site site )
			throws DocumentException
	{
		for ( Floor floor : Floor.values() )
		{
			Paragraph paragraphTitle = this.addPageTitle(floor);
			PdfPTable table = this.addTable(floor, site);

			document.add(paragraphTitle);
			document.add(table);
			document.newPage();
		}
	}

	/**
	 * 
	 * @param floor
	 *            creates table according to floor
	 * @param site
	 *            from which information will be download
	 * @return PdfPTable with site info
	 * @throws BadElementException
	 */
	private PdfPTable addTable ( Floor floor, Site site )
			throws BadElementException
	{
		PdfPTable table = new PdfPTable(3);
		PdfPCell headerCell = new PdfPCell(new Phrase(PdfGenerator.TABLE_HEADER_ROW));
		headerCell.setHorizontalAlignment(Element.ALIGN_CENTER);
		table.addCell(headerCell);

		headerCell = new PdfPCell(new Phrase(PdfGenerator.TABLE_HEADER_COLUMN));
		headerCell.setHorizontalAlignment(Element.ALIGN_CENTER);
		table.addCell(headerCell);

		headerCell = new PdfPCell(new Phrase(PdfGenerator.TABLE_HEADER_STATUS));
		headerCell.setHorizontalAlignment(Element.ALIGN_CENTER);
		table.addCell(headerCell);
		table.setHeaderRows(1);

		Iterator <Lot> iterator = site.getParkingMatrix().getFloorLots(floor);
		while ( iterator.hasNext() )
		{
			Lot lot = iterator.next();

			PdfPCell contentCell = new PdfPCell(new Phrase(String.valueOf(lot.getRow())));
			contentCell.setHorizontalAlignment(Element.ALIGN_CENTER);
			table.addCell(contentCell);

			contentCell = new PdfPCell(new Phrase(String.valueOf(lot.getColumn())));
			contentCell.setHorizontalAlignment(Element.ALIGN_CENTER);
			table.addCell(contentCell);

			contentCell = new PdfPCell(new Phrase(lot.getLotStatus().toString()));
			contentCell.setHorizontalAlignment(Element.ALIGN_CENTER);
			table.addCell(contentCell);
		}

		return table;
	}

	/**
	 * 
	 * @param floor
	 *            as page title
	 * @return titled Paragraph
	 */
	private Paragraph addPageTitle ( Floor floor )
	{
		Paragraph titledParagraph = new Paragraph("Floor:" + floor.toString(), PdfGenerator.siteNameFont);
		titledParagraph.setAlignment(Element.ALIGN_CENTER);

		// adding spacing
		this.addEmptyLine(titledParagraph, 5);

		return titledParagraph;
	}

	/**
	 * 
	 * @param paragraph
	 *            from which to make spacing
	 * @param number
	 *            of spaces to create
	 */
	private void addEmptyLine ( Paragraph paragraph, int number )
	{
		for ( int i = 0; i < number; i ++ )
		{
			paragraph.add(new Paragraph(" "));
		}
	}
}
